﻿using System;
using CI;
using CI.Interfaces;
using CI.Misc;
using NUnit.Framework;

namespace Mesopotamia.UnitTests.Neural
{
    [TestFixture]
    public class StepNeuronTests
    {
        CI.Organism.StepNeuron _stepNeuron;
        const Int64 THRESHOLD_VALUE = 100;
        CI.Organism.SimpleSynapse _inputSynapse1;
        CI.Organism.SimpleSynapse _inputSynapse2;
        CI.Organism.SimpleSynapse _outputSynapse1;
        CI.Organism.SimpleSynapse _outputSynapse2;
        CI.Organism.SimpleNeuralSystem _sns;
        private readonly IHostingEnvironment _hostingEnvironment = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), new CI.Mesopotamia.ScenarioLocalXML());
        readonly SimEnv _simEnv = SimEnv.Instance;

        [SetUp]
        public void Setup()
        {
            // create a neuron and structure
            _hostingEnvironment.Organisms = new CI.Organism.OrganismCollection();
            _sns = new CI.Organism.SimpleNeuralSystem(new CI.Organism.Organism(_hostingEnvironment));
            _stepNeuron = new CI.Organism.StepNeuron(THRESHOLD_VALUE, _sns, Guid.NewGuid());


            _inputSynapse1 = new CI.Organism.SimpleSynapse(Guid.NewGuid(), _sns);
            _inputSynapse2 = new CI.Organism.SimpleSynapse(Guid.NewGuid(), _sns);
            _outputSynapse1 = new CI.Organism.SimpleSynapse(Guid.NewGuid(), _sns);
            _outputSynapse2 = new CI.Organism.SimpleSynapse(Guid.NewGuid(), _sns);

            // add input and output synapse
            _stepNeuron.InputSynapse.Add(_inputSynapse1);
            _stepNeuron.OutputSynapse.Add(_outputSynapse1);

            _inputSynapse1.AddSynapticConnectionTarget(_stepNeuron);
            _outputSynapse1.AddSynapticConnectionSource(_stepNeuron);

            _sns.AddNeuron(_stepNeuron);

        }

        /// <summary>
        /// We should see activation in the output synapse
        /// when the result is high above the thresold
        /// </summary> 
        [Test]
        public void ActivationHighTrue()
        {
            // setup the input
            _inputSynapse1.InputValue = THRESHOLD_VALUE + 1;

            // cycle the neuron activation
            Assert.IsTrue(_stepNeuron.ActivationFunction(1), "Activation result");

            // evaluate it
            _outputSynapse1.Evaluate(99);

            // check the output synapse
            Assert.Greater(_outputSynapse1.OutputValue, 0, "Output value from neuron activation");
        }

        /// <summary>
        /// We should see actication in the output synapse
        /// when the results is equal to the thresold
        /// </summary>
        [Test]
        public void ActivationEqualTrue()
        {
            // setup the input
            _inputSynapse1.InputValue = THRESHOLD_VALUE;

            // cycle the neuron activation
            Assert.IsTrue(_stepNeuron.ActivationFunction(1), "Activation result");

            // evaluate it
            _outputSynapse1.Evaluate(99);

            // check the output synapse
            Assert.Greater(_outputSynapse1.OutputValue, 0, "Output value from neuron activation");
        }

        /// <summary>
        /// We should see not see activation in the output synapse
        /// when the result is below the thresold
        /// </summary>
        [Test]
        public void ActivationLowFalse()
        {
            // setup the input
            _inputSynapse1.InputValue = THRESHOLD_VALUE - 1;

            // cycle the neuron activation
            Assert.IsFalse(_stepNeuron.ActivationFunction(1), "Activation result");

            // evaluate it
            _outputSynapse1.Evaluate(99);

            // check the output synapse
            Assert.AreEqual(_outputSynapse1.OutputValue, 0, "Output value from neuron activation");
        }


    }
}